package com.apes.scm.account.account.service;

import com.alibaba.fastjson.JSON;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.BaseModel;
import com.apes.framework.jpa.repository.CustomRepository;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.OutboxEventService;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.util.JpaUtil;
import com.apes.framework.util.MD5Util;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.ReflectUtil;
import com.apes.scm.account.account.model.*;
import com.apes.scm.account.account.repository.BatchOfFrozenRepository;
import com.apes.scm.account.account.repository.InventoryBatchRepository;
import com.apes.scm.account.method.Batch;
import com.apes.scm.account.method.BatchMethod;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.model.ProductUom;
import com.apes.scm.pur.priceChange.PriceChangeMode;
import com.apes.scm.pur.purchaseOrder.model.PurchaseOrderItem;
import com.apes.scm.pur.purchaseOrder.repository.PurchaseOrderItemRepository;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.repository.VoucherItemRepository;
import com.apes.scm.voucher.repository.VoucherRepository;
import com.apes.scm.voucher.service.VoucherType;
import com.apes.scm.voucher.service.builder.SaleOrderVoucherBuilder;
import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.persistence.EntityManager;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 功能：库存价值服务
 *
 * @author xul
 * @create 2018-03-13 9:17
 */
@Service("inventoryService")
public class InventoryService {

    @Autowired
    private InventoryBatchRepository inventoryBatchRepository;

    @Autowired
    private BatchOfFrozenRepository batchOfFrozenRepository;

    @Autowired
    private InventoryConsignService inventoryConsignService;

    /**
     * 功能：商品库存价值创建
     */
    public InventoryBatch create(InventoryBatch inventoryBatch) {
        return save(inventoryBatch);
    }

//    /**
//     * 功能：查找销售商品库存价值
//     */
//    public List<InventoryBatch> findBySaleInventory(PartyRole company, Product product) {
//        return inventoryBatchRepository.findByCompanyAndProductAndBalanceQtyGreaterThanOrderByBatchNumberAscBatchSerialAsc(company, product, 0);
//    }
//
//    /**
//     * 功能：查找销售商品库存价值
//     */
//    public List<InventoryBatch> findBySaleInventory(PartyRole company, PartyRole supplier, Product product) {
//        return inventoryBatchRepository.findByCompanyAndSupplierAndProductAndBalanceQtyGreaterThanOrderByBatchNumberAscBatchSerialAsc(company, supplier, product, 0);
//    }

    /**
     * 功能：查找销售商品库存价值
     */
    public List<InventoryBatch> findInventoryBatchForSaleOrder(PartyRole company, Dept dept, PartyRole supplier, Product product) {
        return inventoryBatchRepository.findInventoryBatchForSaleOrder(company, dept, supplier, product);
    }

    /**
     * 功能：查找销售商品库存价值
     */
    public List<InventoryBatch> findInventoryBatchForSaleOrder(PartyRole company, Dept dept, Product product) {
        return inventoryBatchRepository.findInventoryBatchForSaleOrder(company, dept, product);
    }

    /**
     * 功能：查找销售退回商品库存价值
     */
    public List<InventoryBatch> findInventoryBatchForSaleReturn(PartyRole company, Dept dept, PartyRole supplier, Product product) {
        return inventoryBatchRepository.findInventoryBatchForSaleReturn(company, dept, supplier, product);
    }

    /**
     * 功能：查找销售退回商品库存价值
     */
    public List<InventoryBatch> findInventoryBatchForSaleReturn(PartyRole company, Dept dept, Product product) {
        return inventoryBatchRepository.findInventoryBatchForSaleReturn(company, dept, product);
    }

    /**
     * 功能：查找采购退货库存
     */
    public List<InventoryBatch> findByPurchaseReturnInventory(PartyRole company, Dept dept, PartyRole supplier, Cooperation cooperation, Product product) {
        return inventoryBatchRepository.findInventoryBatchForPurchaseReturn(company, dept, supplier, cooperation, product);
    }

    /**
     * 功能：查找采购退货库存
     */
    public List<InventoryBatch> findByPurchaseReturnInventory(PartyRole company, PartyRole supplier, Product product) {
        return inventoryBatchRepository.findInventoryBatchForPurchaseReturn(company, supplier, product);
    }

    public InventoryBatch findOne(long id) {
        return inventoryBatchRepository.findOne(id);
    }

    /**
     * 功能：存货计价方法
     */
    public String getCostingMethod(PartyRole company, Product product) {
        return CostingType.CM_FIFO;
    }

    public List<InventoryBatch> findAllByBatchNumber(List<Long> batchNumbers, Function<InventoryBatch, Double> function) {
        return inventoryBatchRepository.findAllByBatchNumberInOrderByBatchNumberAscBatchSerialAsc(batchNumbers)
                .stream()
                .filter(inventoryBatch -> function.apply(inventoryBatch) > 0)
                .collect(Collectors.toList());
    }


    public Collection<Batch> wrapBatch(List<InventoryBatch> inventories, ProductUom toUom, Function<InventoryBatch, Double> function) {
        return inventories.stream()
                .filter(inventoryBatch -> function.apply(inventoryBatch) > 0)
                .map(inventoryBatch -> {
                    Batch batch = new Batch();
                    batch.setEntity(inventoryBatch);
                    double qty = inventoryBatch.getUom().computeQty(function.apply(inventoryBatch), toUom, true);
                    batch.setQty(qty);
                    return batch;
                }).collect(Collectors.toList());
    }

    /**
     * 功能：获取商品批次的最大序号
     *
     * @param oldBatch
     * @return
     */
    private Integer getMaxBatchSerial(InventoryBatch oldBatch) {
        return inventoryBatchRepository.findMaxBatchSerial(oldBatch.getProduct().getId(), oldBatch.getBatchNumber());
    }

    /**
     * 功能：采购变价商品价值评估
     */
    public InventoryVo priceChangeEvaluate(InventoryVo inventoryVo) throws RuntimeException {
        InventoryBatch oldBatch = findOne(inventoryVo.getInInventories().get(0).getId());

        InventoryBatch newBatch = new InventoryBatch();
        newBatch.setCompany(oldBatch.getCompany());
        newBatch.setDept(oldBatch.getDept());
        newBatch.setSupplier(oldBatch.getSupplier());
        newBatch.setProduct(oldBatch.getProduct());
        newBatch.setUom(oldBatch.getUom());
        newBatch.setBatchNumber(oldBatch.getBatchNumber());
        newBatch.setBatchSerial(getMaxBatchSerial(oldBatch));
        newBatch.setContract(oldBatch.getContract());
        newBatch.setCooperation(oldBatch.getCooperation());
        newBatch.setTax(oldBatch.getTax());
        newBatch.setProtocol(oldBatch.getProtocol());
        newBatch.setProtocolType(oldBatch.getProtocolType());
        newBatch.setPurchaseInDate(oldBatch.getPurchaseInDate());
        newBatch.setTaxCostPrice(inventoryVo.getTaxCostPrice());
        newBatch.setNoTaxCostPrice(inventoryVo.getTaxCostPrice() * 100 / (100 + oldBatch.getTax().getAmt()));

        double totalQty = inventoryVo.getQty();
        oldBatch.setPriceChangeQty(oldBatch.getPriceChangeQty() - totalQty);
        newBatch.setPriceChangeQty(totalQty);
        if (PriceChangeMode.PCM_SALES_FIRST.equals(inventoryVo.getPriceChangeMode().getCode())) {  //销售优先
            if (oldBatch.getSalesQty() >= totalQty) { //当批次销售数量大于等于总变价数量时
                newBatch.setSalesQty(totalQty);
                oldBatch.setSalesQty(oldBatch.getSalesQty() - totalQty);
                totalQty = 0;
            } else {                                   //当批次销售数量小于总变价数量时
                newBatch.setSalesQty(oldBatch.getSalesQty());
                totalQty = totalQty - oldBatch.getSalesQty();
                oldBatch.setSalesQty(0);
            }
            if (oldBatch.getBalanceQty() >= totalQty) {
                newBatch.setBalanceQty(totalQty);
                oldBatch.setBalanceQty(oldBatch.getBalanceQty() - totalQty);
                totalQty = 0;
            } else {
                newBatch.setBalanceQty(oldBatch.getBalanceQty());
                totalQty = totalQty - oldBatch.getBalanceQty();
                oldBatch.setBalanceQty(0);
            }
            if (totalQty > 0) {
                oldBatch.setProfitAndLossQty(oldBatch.getProfitAndLossQty() + totalQty);
                newBatch.setProfitAndLossQty(-totalQty);
            }
        } else if (PriceChangeMode.PCM_STOCK_FIRST.equals(inventoryVo.getPriceChangeMode().getCode())) {  //库存优先
            if (oldBatch.getBalanceQty() >= totalQty) {
                newBatch.setBalanceQty(totalQty);
                oldBatch.setBalanceQty(oldBatch.getBalanceQty() - totalQty);
                totalQty = 0;
            } else {
                newBatch.setBalanceQty(oldBatch.getBalanceQty());
                totalQty = totalQty - oldBatch.getBalanceQty();
                oldBatch.setBalanceQty(0);
            }
            if (oldBatch.getSalesQty() >= totalQty) {
                newBatch.setSalesQty(totalQty);
                oldBatch.setSalesQty(oldBatch.getSalesQty() - totalQty);
                totalQty = 0;
            } else {
                newBatch.setSalesQty(oldBatch.getSalesQty());
                totalQty = totalQty - oldBatch.getSalesQty();
                oldBatch.setSalesQty(0);
            }
            if (totalQty > 0) {
                oldBatch.setProfitAndLossQty(oldBatch.getProfitAndLossQty() + totalQty);
                newBatch.setProfitAndLossQty(-totalQty);
            }
        } else {
            throw new RuntimeException("【变价方式】不是有效的值！");
        }

        double frostQty = oldBatch.getFrostQty() - oldBatch.getBalanceQty();
        if (frostQty > 0) {
            oldBatch.changeFrostQty(-1 * frostQty);
            newBatch.changeFrostQty(frostQty);
        }
        save(oldBatch);
        save(newBatch);
        inventoryVo.getInInventories().clear();
        inventoryVo.getInInventories().add(oldBatch);
        inventoryVo.setOutInventoryBatch(newBatch);
        priceChangeEvaluateForCustomerConsign(oldBatch, newBatch.getTaxCostPrice(), newBatch.getBalanceQty(), newBatch.getSalesQty(), newBatch.getProfitAndLossQty()); /**调整内部供应商寄售客户库存价格**/
        return inventoryVo;
    }

    /**
     * 调整内部供应商寄售客户库存价格
     **/
    private void priceChangeEvaluateForCustomerConsign(InventoryBatch oldBatch, double taxCostPrice, double balanceQty, double salesQty, double profitAndLossQty) {
        /**内部供应商并且寄售**/
        if (!oldBatch.getSupplier().getParty().getCorporate().inner() || !oldBatch.getCooperation().getInventoryMode().equals(InventoryMode.IM_CONSIGN)) {
            return;
        }

        PartyRole company = SpringManager.getBean(SaleOrderVoucherBuilder.class).getCompany(oldBatch.getSupplier());
        PartyRole customer = SpringManager.getBean(SaleOrderVoucherBuilder.class).getCustomer(oldBatch.getCompany());

        /**变库存**/
        if (balanceQty != 0) {
            new BatchMethod<Batch>() {
                @Override
                public Iterable<Batch> wrap() {
                    List<InventoryConsign> inventoryConsigns = inventoryConsignService.findInventoryConsignForOrder(company, customer, oldBatch.getProduct(), oldBatch.getTaxCostPrice());
                    return inventoryConsignService.wrapBatch(inventoryConsigns, oldBatch.getUom(), inventoryConsign -> inventoryConsign.getBalanceQty() - inventoryConsign.getFrostBalanceQty());
                }

                @Override
                public void succeed(Batch batch, double increment) {
                    InventoryConsign oldInventoryConsign = (InventoryConsign) batch.getEntity();
                    double qty = oldBatch.getUom().computeQty(increment, oldInventoryConsign.getUom(), true);
                    double price = oldBatch.getUom().computePrice(taxCostPrice, oldInventoryConsign.getUom());
                    oldInventoryConsign.changePriceChangeQty(qty); /**变价数量增加**/
                    oldInventoryConsign.changeBalanceQty(-1 * qty); /**结存数量增加**/
                    oldInventoryConsign = inventoryConsignService.save(oldInventoryConsign);
                    createInventoryConsign(oldInventoryConsign, price, qty, qty, 0);
                }

                @Override
                public void error(double surplus) {
                    throw new RuntimeException("商品：[" + oldBatch.getProduct().getId() + "]" + oldBatch.getProduct().getName() + " 结存数量少 " + surplus + oldBatch.getUom().getName() + "！");
                }
            }.execute(balanceQty);
        }

        /**变销售**/
        if (salesQty != 0 || profitAndLossQty != 0) {
            new BatchMethod<Batch>() {
                @Override
                public Iterable<Batch> wrap() {
                    List<InventoryConsign> inventoryConsigns = inventoryConsignService.findInventoryConsignForReturn(company, customer, oldBatch.getProduct(), oldBatch.getTaxCostPrice());
                    return inventoryConsignService.wrapBatch(inventoryConsigns, oldBatch.getUom(), inventoryConsign -> inventoryConsign.getConsumeQty() - inventoryConsign.getFrostConsumeQty());
                }

                @Override
                public void succeed(Batch batch, double increment) {
                    InventoryConsign oldInventoryConsign = (InventoryConsign) batch.getEntity();
                    double qty = oldBatch.getUom().computeQty(increment, oldInventoryConsign.getUom(), true);
                    double price = oldBatch.getUom().computePrice(taxCostPrice, oldInventoryConsign.getUom());
                    oldInventoryConsign.changePriceChangeQty(qty); /**变价数量增加**/
                    oldInventoryConsign.changeConsumeQty(-1 * qty); /**消耗数量增加**/
                    oldInventoryConsign = inventoryConsignService.save(oldInventoryConsign);
                    createInventoryConsign(oldInventoryConsign, price, qty, 0, qty);
                }

                @Override
                public void error(double surplus) {
                    throw new RuntimeException("商品：[" + oldBatch.getProduct().getId() + "]" + oldBatch.getProduct().getName() + " 消耗数量少 " + surplus + oldBatch.getUom().getName() + "！");
                }
            }.execute(Math.abs(salesQty) + Math.abs(profitAndLossQty));
        }
    }


    @Autowired
    private EntityManager em;


    public void init(SimpleRequest request) {
        String sql = "select b.id, b.product_id, b.old_batch_id, b.new_price_unit, b.change_balance_qty,\n" +
                "       b.change_sales_qty, b.change_Profit_Loss_qty\n" +
                "  from pur_price_change a, pur_price_change_item b, acc_inventory_batch c\n" +
                " where a.id = b.price_change_id\n" +
                "   and a.company_id != '1001'\n" +
                "   and a.supplier_id = 'A1001'\n" +
                "   and b.old_batch_id = c.id\n" +
                "   and c.cooperation_id = 'consignment'\n" +
                "   and a.state = 'done' \n" +
                "   and not exists (select 1 from pur_price_change_tz20220627 where id = b.id)";
        em.createNativeQuery(sql).unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).getResultList().stream().forEach(m -> {
            try {
                transactionTemplate.execute(status -> {
                    InventoryBatch oldBatch = findOne(((BigDecimal) ((Map) m).get("OLD_BATCH_ID")).longValue());
                    double taxCostPrice = ((BigDecimal) ((Map) m).get("NEW_PRICE_UNIT")).doubleValue();
                    double balanceQty = ((BigDecimal) ((Map) m).get("CHANGE_BALANCE_QTY")).doubleValue();
                    double salesQty = ((BigDecimal) ((Map) m).get("CHANGE_SALES_QTY")).doubleValue();
                    double profitAndLossQty = ((BigDecimal) ((Map) m).get("CHANGE_PROFIT_LOSS_QTY")).doubleValue();
                    priceChangeEvaluateForCustomerConsign(oldBatch, taxCostPrice, balanceQty, salesQty, profitAndLossQty);

                    inventoryBatchRepository.exec("insert into pur_price_change_tz20220627(id)  values(" + ((BigDecimal) ((Map) m).get("ID")).longValue() +")");
                    return null;
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    /**
     *
     * @param oldInventoryConsign  原寄售库存
     * @param priceUnit   价格
     * @param consignQty  寄售数量
     * @param balanceQty  结存数量
     * @param consumeQty  消耗
     * @return
     */
    private InventoryConsign createInventoryConsign(InventoryConsign oldInventoryConsign, double priceUnit, double consignQty, double balanceQty, double consumeQty) {
        InventoryConsign inventoryConsign = new InventoryConsign();
        inventoryConsign.setBatchNumber(oldInventoryConsign.getBatchNumber());
        inventoryConsign.setBatchSerial(inventoryConsignService.getMaxBatchSerial(oldInventoryConsign));
        inventoryConsign.setCompany(oldInventoryConsign.getCompany());
        inventoryConsign.setDept(oldInventoryConsign.getDept());
        inventoryConsign.setCustomer(oldInventoryConsign.getCustomer());
        inventoryConsign.setProduct(oldInventoryConsign.getProduct());
        inventoryConsign.setUom(oldInventoryConsign.getUom());
        inventoryConsign.setTax(oldInventoryConsign.getTax());
        inventoryConsign.setPriceUnit(priceUnit);
        inventoryConsign.setConsignQty(consignQty);
        inventoryConsign.changeBalanceQty(balanceQty);
        inventoryConsign.changeConsumeQty(consumeQty);
        inventoryConsign.setInventoryBatch(oldInventoryConsign.getInventoryBatch());
        return inventoryConsignService.save(inventoryConsign);
    }

    public boolean isSureInventories(InventoryVo inventoryVo) {
        return inventoryVo.getInInventories() != null && !inventoryVo.getInInventories().isEmpty();
    }


    public InventoryBatch save(InventoryBatch inventoryBatch) {
        return inventoryBatchRepository.saveAndFlush(inventoryBatch);
    }

    public Map findChangePriceAbleBatch(SimpleRequest request) {
//        String deptId = request.get("deptId");
        String supplierId = request.get("supplierId");
        String productId = request.get("productId");
        String cooperationId = request.get("cooperationId");
        List<InventoryBatch> inventoryBatchList = inventoryBatchRepository.findChangePriceAbleBatch(/*deptId,*/ supplierId, productId, cooperationId);
        return MapUtil.mapper("content", inventoryBatchList);
    }

    /**
     * 写批次冻结数
     **/
    public void changeFrostQty(InventoryBatch inventoryBatch, ProductUom uom, double changeQty,
                               PartyRole company, String sourceBusinessType, String orderNumber,
                               String orderSerialNumber, String remarks) {
        double frostQty = uom.computeQty(changeQty, inventoryBatch.getUom(), true);
        changeFrostQty(inventoryBatch, frostQty, company, sourceBusinessType, orderNumber, orderSerialNumber, remarks);
    }

    /**
     * 写批次冻结数
     *
     * @param inventoryBatch
     * @param changeQty
     * @param company
     * @param sourceBusinessType
     * @param orderNumber
     * @param orderSerialNumber
     * @param remarks
     */
    private void changeFrostQty(InventoryBatch inventoryBatch, double changeQty,
                                PartyRole company,
                                String sourceBusinessType, String orderNumber,
                                String orderSerialNumber, String remarks) {

        //  增加（减少）冻结数量
        inventoryBatch.changeFrostQty(changeQty);
        // 更新批次信息
        InventoryBatch batch = inventoryBatchRepository.saveAndFlush(inventoryBatch);
        //写入批次冻结数明细帐
        saveBatchOfFrozen(batch, changeQty, company, sourceBusinessType, orderNumber, orderSerialNumber, remarks);
        //写入解冻数
        if (changeQty < 0) {
            writeThawingQty(batch, changeQty, sourceBusinessType, orderNumber);
        }
    }

    /**
     * 写入解冻数
     *
     * @param inventoryBatch
     * @param changeQty
     * @param sourceBusinessType
     * @param orderNumber
     */
    public void writeThawingQty(InventoryBatch inventoryBatch, double changeQty, String sourceBusinessType, String orderNumber) {
        if (Objects.isNull(sourceBusinessType) || Objects.isNull(orderNumber)) {
            return;
        }
        //获取原始冻结明细行
        BatchOfFrozen batchOfFrozen = batchOfFrozenRepository.findBySource(sourceBusinessType, orderNumber, inventoryBatch.getId()).stream().findFirst().orElse(null);
        if (Objects.nonNull(batchOfFrozen)) {
            //写入解冻数
            batchOfFrozen.addThawingQty(changeQty * -1);
            batchOfFrozenRepository.saveAndFlush(batchOfFrozen);
            return;
        }
        //获取实体的领域类
        String domainTypeName = JpaUtil.getAllDomainType().stream()
                .filter(s -> ReflectUtil.getClass(s).getSimpleName().equalsIgnoreCase(sourceBusinessType))
                .findFirst().orElse(null);
        if (domainTypeName == null) {
            //找不到sourceBusinessType对应实体领域类
            return;
        }
        CustomRepository<BaseModel, Serializable> repository = JpaUtil.getRepository(domainTypeName);
        Serializable id = JpaUtil.getId(domainTypeName, orderNumber);
        BaseModel model = (repository != null ? repository.findOne(id) : null);
        if (model == null) {
            //根据orderNumber找不到该数据表中对应数据
            return;
        }
        String businessType = ReflectUtil.getFieldValue(model, "sourceBusinessType");
        // server转ServicePlan
        // 此处转换是因为在系统中已经把server当ServicePlan使用了 不知道为什么这样做 不转换无法溯源
        if ("server".equals(businessType)) {
            businessType = "ServicePlan";
        }
        String source = ReflectUtil.getFieldValue(model, "source");
        if (Objects.isNull(businessType) && Objects.isNull(source)) {
            businessType = ReflectUtil.getFieldValue(model, "originBusinessType");
            source = ReflectUtil.getFieldValue(model, "origin");
        }
        writeThawingQty(inventoryBatch, changeQty, businessType, source);
    }

    /**
     * 写入批次冻结数明细帐
     *
     * @param inventoryBatch
     * @param changeQty
     * @param company
     * @param sourceBusinessType
     * @param orderNumber
     * @param orderSerialNumber
     * @param remarks
     */
    public BatchOfFrozen saveBatchOfFrozen(InventoryBatch inventoryBatch, double changeQty, PartyRole company, String sourceBusinessType, String orderNumber,
                                           String orderSerialNumber, String remarks) {
        BatchOfFrozen batchOfFrozen = new BatchOfFrozen();
        batchOfFrozen.setBatchId(inventoryBatch.getId());
        batchOfFrozen.setBatchNumber(inventoryBatch.getBatchNumber());
        batchOfFrozen.setProduct(inventoryBatch.getProduct());
        batchOfFrozen.setUom(inventoryBatch.getUom());
        batchOfFrozen.setCompany(company);
        batchOfFrozen.setChangeQty(changeQty);
        batchOfFrozen.setSourceBusinessType(sourceBusinessType);
        batchOfFrozen.setOrderNumber(orderNumber);
        batchOfFrozen.setOrderSerialNumber(orderSerialNumber);
        batchOfFrozen.setRemarks(remarks);
        batchOfFrozen.setFrozenQty(inventoryBatch.getFrostQty());
        if (changeQty > 0) {
            batchOfFrozen.setSourceType(sourceBusinessType);
            batchOfFrozen.setSource(orderNumber);
            batchOfFrozen.setSourceNumber(orderSerialNumber);
            if (Objects.equals("Voucher", sourceBusinessType)) {
                //来源为凭证的单独处理 直接溯源
                Voucher voucher = SpringManager.getBean(VoucherRepository.class).findOne(orderNumber);
                if (voucher != null) {
                    String originBusinessType = voucher.getOriginBusinessType();
                    String origin = voucher.getOrigin();
                    batchOfFrozen.setSourceType(originBusinessType);
                    batchOfFrozen.setSource(origin);
                    if (Objects.isNull(originBusinessType) || Objects.isNull(origin)) {
                        batchOfFrozen.setSourceType(voucher.getSourceBusinessType());
                        batchOfFrozen.setSource(voucher.getSource());
                    }
                    batchOfFrozen.setSourceNumber(null);
                }
            }
        }
        return batchOfFrozenRepository.saveAndFlush(batchOfFrozen);
    }


    /**
     * 批次定期替换真实供应商编码
     *
     * @param request
     */
    public void replaceSuppliersRegularly(SimpleRequest request) {
        inventoryBatchRepository.findBySupplierAndMinCreateDate().stream().findFirst().ifPresent(inventory -> {
            int page = 0;
            int size = 2000;
            Sort sort = new Sort(Sort.Direction.ASC, "createDate");
            Date createDate = inventory.getCreateDate();
            long id = inventory.getId();
            while (true) {
                Pageable pageable = PageRequest.of(page, size, sort);
                Page<InventoryBatch> inventoryBatches = inventoryBatchRepository.findAllBySupplierIdOrderById(VoucherType.SUPPLIER_CODE, id, createDate, pageable);
                List<InventoryBatch> content = inventoryBatches.getContent();
                if (content != null && content.size() > 0) {
                    for (InventoryBatch inventoryBatch : content) {
                        execute(() -> {
                            VoucherItem vItem = SpringManager.getBean(VoucherItemRepository.class).findOne(inventoryBatch.getBatchNumber());
                            if (Objects.nonNull(vItem)) {
                                if (Objects.equals(vItem.getVoucher().getOriginBusinessType(), "PurchaseOrder")) {
                                    PurchaseOrderItem orderItem = SpringManager.getBean(PurchaseOrderItemRepository.class).findOne(Long.valueOf(vItem.getOriginItemId()));
                                    if (Objects.nonNull(orderItem.getName())) {
                                        String name = orderItem.getName();
                                        String supplierId = name;
                                        if (!name.matches(".*[a-zA-Z].*") && name.length() >= 8) {
                                            supplierId = name.substring(name.length() - 6);
                                        }
                                        PartyRole supplier = SpringManager.getBean(PartyRoleRepository.class).findOne(supplierId);
                                        if (Objects.nonNull(supplier)) {
                                            inventoryBatch.setOriginalSupplier(supplier);
                                            inventoryBatchRepository.save(inventoryBatch);

                                        }
                                    }
                                }
                            }
                        });
                        createDate = inventoryBatch.getCreateDate();
                        id = inventoryBatch.getId();

                    }
                }
                if ((content != null ? content.size() : 0) < 2000) {
                    break;
                }
            }
        });
    }

    @Autowired
    private TransactionTemplate transactionTemplate;

    public void execute(Callback callback) {
        transactionTemplate.execute(status -> {
            try {
                callback.execute();
                return null;
            } catch (Exception e) {
                status.isRollbackOnly();
                throw e;
            }
        });
    }

    @FunctionalInterface
    public interface Callback {
        @Nullable
        void execute();
    }


    // 查找冻结明细
    public List<BatchOfFrozen> findByCurrentNumber(SimpleRequest request) {
        Map getJO = request.getMap();
        return batchOfFrozenRepository.findByCurrentNumber(getJO.get("sourceBusinessType").toString(), getJO.get("orderNumber").toString(), getJO.get("productId").toString());
    }
}
